const utils = {
	ifNullAsVal: function(src, prop, useVal){
		if(null == src || null == src[prop]){
			return useVal;
		}
		return src[prop];

	},

	notEmpty: function(val){
		return null != val && '' != val;

	}

};

const state = {snapshotMap:{}};

const buildSnapshotMap = (domMap) => {
	let snapshotMap = {};
	for(let key in domMap){
		let node = domMap[key];
		let nodeRef = snapshotMap[node.id];
		let tmpNode = {
			id: node.id,
			pid: node.pid,
			psid: node.psid,
			nsid: node.nsid,
			childOpen: false,
			type: utils.ifNullAsVal(node, 'nodeType', 0),
			name: utils.ifNullAsVal(node, 'nodeName', 'EMPTY'),
			value: utils.ifNullAsVal(node, 'nodeValue', ''),
			childNodes: [],
			childMap: {}
		};
		if(null == nodeRef){
			snapshotMap[node.id] = tmpNode;
		}
	}
	return snapshotMap;

};

const buildSnapshotTree = (snapshotMap) => {
	let root = {
		id: 0,
		name: 'ROOT',
		level: 0,
		childOpen: true,
		childNodes: [],
		childMap: {}
	};
	for(let key in snapshotMap){
		let nodeRef = snapshotMap[key];
		let parentRef = null == snapshotMap[nodeRef.pid] ? root : snapshotMap[nodeRef.pid];
		if(null == parentRef.childMap[nodeRef.id]){
			let appended = false;
			let siblingNodes = parentRef.childNodes;
			for(let i = 0; i < siblingNodes.length; i++){
				let siblingNode = siblingNodes[i];
				if(0 != nodeRef.psid && nodeRef.psid == siblingNode.id){
					siblingNodes.splice((i + 1), 0, nodeRef);
					appended = true;
					break;
				}
				if(0 != nodeRef.nsid && nodeRef.nsid == siblingNode.id){
					siblingNodes.splice(i, 0, nodeRef);
					appended = true;
					break;
				}
			}
			if(!appended){
				siblingNodes.push(nodeRef);
			}
			nodeRef.level = parentRef.level + 1;
			parentRef.childMap[nodeRef.id] = nodeRef;
		}
	}
	return root;

};

const buildDeltaSnapshotTree = (nodeUpdates) => {
	let snapshotMap = state.snapshotMap;
	let addedDeltas = nodeUpdates.added;
	let removedDeltas = nodeUpdates.removed;
	let deltaUpdateMap = {};
	if(null != removedDeltas && Object.keys(removedDeltas).length > 0){
		let deltaSnapshot = buildSnapshot(removedDeltas);
		let deltaSnapshotRoot = buildSnapshotTree(deltaSnapshot);
		for(let key in deltaSnapshot){
			snapshotMap[key] = deltaSnapshot[key];
		}
		deltaUpdateMap.removed = deltaSnapshotRoot;
	}		
	if(null != addedDeltas && Object.keys(addedDeltas).length > 0){
		let deltaSnapshot = buildSnapshot(addedDeltas);
		let deltaSnapshotRoot = buildSnapshotTree(deltaSnapshot);
		for(let key in deltaSnapshot){
			if(null != snapshotMap[key]){
				delete snapshotMap[key];
			}
		}
		deltaUpdateMap.added = deltaSnapshotRoot;
	}
	deltaUpdateMap.snapshotMap = snapshotMap;
	return deltaUpdateMap;

};

const executeSnapshotUpdate = (domMap) => {
	let snapshotMap = buildSnapshotMap(domMap);
	let snapshotTreeRoot = buildSnapshotTree(snapshotMap);
	state.snapshotMap = snapshotMap;
	return snapshotTreeRoot;

};

const executeDeltaSnapshotUpdate = (deltaUpdates) => {
	let snapshotTreeRoot = {};
	let nodeUpdates = null == deltaUpdates || null == deltaUpdates.nodeUpdates ? {} : deltaUpdates.nodeUpdates;
	if(null != nodeUpdates.added || null != nodeUpdates.removed){
		snapshotTreeRoot = buildDeltaSnapshotTree(nodeUpdates);
		state.snapshotMap = snapshotTreeRoot.snapshotMap;
	}
	return snapshotTreeRoot;

};


module.exports = {
	buildTree: executeSnapshotUpdate,
	buildDeltaTree: executeDeltaSnapshotUpdate

};